﻿using LitJson;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using TRC;
using UnityEngine;

namespace BrokenDelusionMod.Manager
{
    /*
def readStr(path,CommandType,ValueKey,listBox):
	f1=open(path,encoding="utf-8")
	jsstr=f1.read()
	f1.close()
	js=json.loads(jsstr)
	for key in js:
		if(js[key]["CommandType"]==CommandType and js[key][ValueKey] not in listBox):
			listBox.append(js[key][ValueKey])
			print(js[key][ValueKey])
            */
    public static class Mod
    {
        static bool isLoad = false;
        static bool isOutCommand = false;
        static ScenarioData[] originalScenarioDatas = null;
        public static void StartCall()
        {
            if (!isLoad)
            {
                isLoad = true;
                Log.iniLog();
                Log.modLog("Mod Initialize Success");
                Log.modLog("Scenario Path:" + Directory.GetCurrentDirectory() + "\\Scenario");
                ReplaceFile();
            }
        }

        struct ModHead
        {
            public string ModName;
            public string ModAuthor;
            public string ModSign;
            public string ModDescription;
            public string ModEntry;
        }
        static ScenarioDataData[] CreateHead(List<ModHead> heads)
        {
            List<ScenarioDataData> result = new List<ScenarioDataData>();
            int page = 0;
            int index = 0;
            result.Add(CreateSafeScenarioDataData(CommandType.Wait));
            result[0].Id = "#Menu_Page0";
            while (index<heads.Count)
            {
                ScenarioDataData data = CreateSafeScenarioDataData(CommandType.Choice);
                if (heads.Count - index > 3)
                {
                    data.Id = "#Menu_Page" + (page + 1).ToString();
                    for (int i = 0; i < 3; i++)
                    {
                        data.Value1 += heads[index + i].ModName + "^#" + heads[index + i].ModName + "_" + heads[index + i].ModSign + "/";
                    }
                    data.Value1 += "下一页^#Menu_Page" + (page + 1).ToString();
                    data.Value2 = data.Value1;
                    data.Value3 = data.Value1;
                }
                else
                {
                    data.Id = "#Menu_Page" + (page + 1).ToString();
                    for (int i = 0; i < heads.Count - index; i++)
                    {
                        data.Value1 += heads[index + i].ModName + "^#" + heads[index + i].ModName + "_" + heads[index + i].ModSign + "/";
                    }
                    data.Value1 += "下一页^#Menu_Page0";
                    data.Value2 = data.Value1;
                    data.Value3 = data.Value1;
                }
                result.Add(data);
                index += 3;
                page += 1;
            }
            for(int i = 0; i < heads.Count; i++)
            {
                ScenarioDataData data = CreateSafeScenarioDataData(CommandType.Jump);
                data.Id = "#" + heads[i].ModName + "_" + heads[i].ModSign;
                data.Value1 = "#ModStart_Mengluu's Sign";
                data.Value2 = heads[i].ModEntry;
                result.Add(data);
            }
            return result.ToArray();
        }
        static ScenarioDataData CreateSafeScenarioDataData(CommandType type)
        {
            ScenarioDataData result = new ScenarioDataData();
            result.COMMANDTYPE = type;
            result.Id = "";
            result.Condition = "";
            result.Text = "";
            result.Value1 = "";
            result.Value2 = "";
            result.Value3 = "";
            result.Value4 = "";
            result.Value5 = "";
            result.Value6 = "";
            result.Value7 = "";
            result.Value8 = "";
            result.Value9 = "";
            result.Value10 ="";
            result.Value11 ="";
            result.Value12 ="";
            result.Value13 ="";
            result.Value14 = "";
            result.Wait = "True";
            return result;
        }
        static ScenarioDataData[] ReadScenario(JsonData json)
        {
            ScenarioDataData[] result = new ScenarioDataData[json.Count];
            for (int i = 0; i < json.Count; i++)
            {
                result[i] = new ScenarioDataData();
                result[i].COMMANDTYPE = (CommandType)Enum.Parse(typeof(CommandType), json[i.ToString()]["CommandType"].ToString());
                result[i].Condition = json[i.ToString()]["Condition"].ToString();
                result[i].Id = json[i.ToString()]["Id"].ToString();
                result[i].Text = json[i.ToString()]["Text"].ToString();
                result[i].Value1 = json[i.ToString()]["Value1"].ToString();
                result[i].Value2 = json[i.ToString()]["Value2"].ToString();
                result[i].Value3 = json[i.ToString()]["Value3"].ToString();
                result[i].Value4 = json[i.ToString()]["Value4"].ToString();
                result[i].Value5 = json[i.ToString()]["Value5"].ToString();
                result[i].Value6 = json[i.ToString()]["Value6"].ToString();
                result[i].Value7 = json[i.ToString()]["Value7"].ToString();
                result[i].Value8 = json[i.ToString()]["Value8"].ToString();
                result[i].Value9 = json[i.ToString()]["Value9"].ToString();
                result[i].Value10 = json[i.ToString()]["Value10"].ToString();
                result[i].Value11 = json[i.ToString()]["Value11"].ToString();
                result[i].Value12 = json[i.ToString()]["Value12"].ToString();
                result[i].Value13 = json[i.ToString()]["Value13"].ToString();
                result[i].Value14 = json[i.ToString()]["Value14"].ToString();
                result[i].Wait = json[i.ToString()]["Wait"].ToString();
            }
            return result;
        }
        static void ReplaceFile()
        {
            Log.modLog("Start Replace");
            GameManager game = GameManager.instance;
            if (game != null)
            {
                FieldInfo[] fieldInfo = typeof(GameManager).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                FieldInfo field = fieldInfo.First(x => x.Name == "_scenarioDatas");
                if(!Directory.Exists(Directory.GetCurrentDirectory() + "\\Scenario"))
                {
                    Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\Scenario");
                }
                string[] tar = Directory.GetFiles(Directory.GetCurrentDirectory() + "\\Scenario");
                if (originalScenarioDatas==null)
                {
                    ScenarioData[] scenarios = (ScenarioData[])field.GetValue(game);
                    originalScenarioDatas = new ScenarioData[scenarios.Length];
                    for(int i = 0; i < scenarios.Length; i++)
                    {
                        if(scenarios[i].name== "ScenarioData")
                        {
                            ScenarioData data = new ScenarioData();
                            data.name = "ScenarioData";
                            data.dataArray = new ScenarioDataData[scenarios[i].dataArray.Length];
                            scenarios[i].dataArray.CopyTo(data.dataArray, 0);
                            originalScenarioDatas[i] = data;
                        }
                        else
                        {
                            originalScenarioDatas[i] = scenarios[i];
                        }
                    }
                }
                List<ScenarioData> scenarioDatas = new List<ScenarioData>();
                List<ModHead> modHead = new List<ModHead>() { new ModHead { ModName = "妄想破绽", ModAuthor = "妄想破绽", ModDescription = "妄想破绽", ModEntry = "ScenarioData", ModSign = "这是一个来自官方的原版剧本" } };
                List<string> loadList = new List<string>();
                foreach(string tarPath in tar)
                {
                    if (Path.GetExtension(tarPath) == ".mod")
                    {
                        JsonData json = JsonMapper.ToObject(File.ReadAllText(tarPath));

                        //在此处创建开头相关
                        modHead.Add(new ModHead { ModName = json["ModName"].ToString(), ModAuthor = json["ModAuthor"].ToString(), ModDescription = json["ModDescription"].ToString(), ModEntry = json["ModEntry"].ToString(), ModSign = json["ModSign"].ToString() });
                        Log.modLog("Load:" + Path.GetFileNameWithoutExtension(tarPath) + "<" + json["ModName"].ToString() + ">   " + "by:" + json["ModAuthor"].ToString() + "   " + json["ModDescription"].ToString());

                        JsonData file = json["ModFile"];
                        foreach (string scenarioName in file.Keys)
                        {
                            if (loadList.Contains(scenarioName))
                            {
                                Log.modLog("Error:" + scenarioName + " has exits!");
                                continue;
                            }
                            else
                            {
                                loadList.Add(scenarioName);
                            }
                            ScenarioData data = new ScenarioData();
                            data.name = scenarioName;
                            //Log.modLog("Load:" + scenarioName);
                            data.dataArray = ReadScenario(file[scenarioName]);
                            /*if (scenarioName == json["ModEntry"].ToString())
                            {
                                ScenarioDataData[] newData = new ScenarioDataData[data.dataArray.Length + 1];
                                newData[0] = CreateSafeScenarioDataData(CommandType.Wait);
                                newData[0].Id = "#ModStart_Mengluu's Sign";
                                data.dataArray.CopyTo(newData, 1);
                            }*/
                            scenarioDatas.Add(data);
                        }
                    }
                    else if (Path.GetExtension(tarPath) == ".json")
                    {
                        string scenarioName = Path.GetFileNameWithoutExtension(tarPath);
                        if (loadList.Contains(scenarioName))
                        {
                            Log.modLog("Error:" + scenarioName + " has exits!");
                            continue;
                        }
                        else
                        {
                            loadList.Add(scenarioName);
                        }
                        JsonData json = JsonMapper.ToObject(File.ReadAllText(tarPath));
                        ScenarioData data = new ScenarioData();
                        data.name = scenarioName;
                        data.dataArray = ReadScenario(json);
                        scenarioDatas.Add(data);
                    }
                }
                foreach(ScenarioData data in originalScenarioDatas)
                {
                    if(data.name== "ScenarioData")
                    {
                        List<ScenarioDataData> newData = new List<ScenarioDataData>();
                        newData.AddRange(CreateHead(modHead));
                        newData.Add(CreateSafeScenarioDataData(CommandType.Wait));
                        newData[newData.Count - 1].Id = "#ModStart_Mengluu's Sign";
                        newData.AddRange(data.dataArray);
                        ScenarioData newScenario = new ScenarioData();
                        newScenario.name = data.name;
                        newScenario.dataArray = newData.ToArray();
                        scenarioDatas.Add(newScenario);
                    }
                    else
                    {
                        scenarioDatas.Add(data);
                    }
                }
                field.SetValue(game, scenarioDatas.ToArray());
                Log.modLog("End Replace");
            }
        }

        //输出指令序号
        public static void OutCommand()
        {
            if (!isOutCommand)
            {
                return;
            }
            //Log.modLog("Start out");
            VnManager vnManager = VnManager.instance;
            //Log.modLog(vnManager.name);
            if (vnManager != null)
            {
                //Log.modLog("Get VnManager");
                FieldInfo[] fieldInfo = vnManager.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                FieldInfo field_currentIndex = fieldInfo.First(x => x.Name == "_currentIndex");
                int currentIndex = (int)field_currentIndex.GetValue(vnManager);
                FieldInfo field_commands = fieldInfo.First(x => x.Name == "_commands");
                List<VnCommand> commands = (List<VnCommand>)field_commands.GetValue(vnManager);

                Log.modLog(currentIndex.ToString());
            }
        }

        //扩充原游戏选项数量
        /*public static void AddChoice()
        {
            Button choiceButton0 = VnManager.instance.choiceButtons[0];

            FieldInfo[] fieldInfo = typeof(ChoiceButton).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            fieldInfo.First(x => x.Name == "_showMoveDistantce").SetValue(choiceButton0.GetComponent<ChoiceButton>(), new float[] { 518, 563, 641, 738, 753, 768, 783, 798 });

            GameObject.Destroy(VnManager.instance.choiceButtons[1]);
            GameObject.Destroy(VnManager.instance.choiceButtons[2]);
            GameObject.Destroy(VnManager.instance.choiceButtons[3]);

            VnManager.instance.choiceButtons = new Button[] { choiceButton0,
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true),
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true),
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true),
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true),
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true),
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true),
                            GameObject.Instantiate(VnManager.instance.choiceButtons[0], VnManager.instance.choiceButtons[0].transform.parent, true), };

            for (int i = 0; i < VnManager.instance.choiceButtons.Length; i++)
            {
                fieldInfo.First(x => x.Name == "_showMoveDuration").SetValue(VnManager.instance.choiceButtons[i].GetComponent<ChoiceButton>(), 1.0f - 0.08f * i);
            }
        }*/

        //指令函数合集
        internal static void Hello()
        {
            Log.modLog("Hello, how are you.");
        }
        internal static bool Jump(int index)
        {
            try
            {
                VnManager vnManager = VnManager.instance;
                GameManager.instance.scenarioJumping = true;
                GameManager.instance.scenarioState = new ScenarioState(vnManager.currentState.ScenarioName, index);
                GameManager.instance.scenarioStateForSave = new ScenarioState(vnManager.currentState.ScenarioName, index);
                GameManager.instance.SwitchToGameState(GameState.Vn);
                return true;
            }
            catch
            {
                return false;
            }
        }
        internal static bool ChangeScene(string ScenarioName, int Index)
        {
            try
            {
                GameManager.instance.scenarioJumping = true;
                GameManager.instance.scenarioState = new ScenarioState(ScenarioName, Index);
                GameManager.instance.scenarioStateForSave = new ScenarioState(ScenarioName, Index);
                GameManager.instance.SwitchToGameState(GameState.Vn);
                return true;
            }
            catch
            {
                return false;
            }
        }
        internal static bool Voice(string VoiceName)
        {
            try
            {
                string cueName, speakerName;
                string cueSheet = Utilitis.GetCueSheetWithCueNameAndSpeaker(VoiceName, out cueName, out speakerName);
                Log.modLog(speakerName + ":" + cueSheet + "." + cueName);
                GameManager.instance.audioManager.PlayVoice(cueName, 5f, cueSheet);
                return true;
            }
            catch
            {
                return false;
            }
        }
        internal static bool Sound(string Name,string CueSheet)
        {
            try
            {
                GameManager.instance.audioManager.MusicControl(Name, "5", false, 1, CueSheet);
                return true;
            }
            catch
            {
                return false;
            }
        }
        internal static bool Stop()
        {
            try
            {
                GameManager.instance.audioManager.StopAllMusic();
                return true;
            }
            catch
            {
                return false;
            }
        }
        internal static void Reload()
        {
            ReplaceFile();
            try
            {
                GameManager.instance.vnCommands.Clear();
                VnManager.instance.commandsWithId.Clear();
                MethodInfo method_LoadScenarioDatas = typeof(GameManager).GetMethod("LoadScenarioDatas", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                method_LoadScenarioDatas.Invoke(GameManager.instance, null);
                GameManager.instance.scenarioJumping = true;
                GameManager.instance.SwitchToGameState(GameState.Vn);
            }
            catch
            {

            }
            
        }
        internal static bool DumpFile(string Path)
        {
            Log.modLog("Start Dump");
            Component component = GameObject.Find("GameManager").GetComponent(typeof(GameManager));
            GameManager game = (GameManager)component;
            if (component != null)
            {
                FieldInfo[] fieldInfo = game.GetType().GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
                FieldInfo field = fieldInfo.First(x => x.Name == "_scenarioDatas");
                ScenarioData[] scenarioscenData = (ScenarioData[])field.GetValue(game);
                foreach (ScenarioData scenario in scenarioscenData)
                {
                    if (!Directory.Exists(Path))
                    {
                        Log.modLog("Don't Find the Path");
                        return false;
                    }
                    string jsonPath = Path + "\\" + scenario.name + ".json";
                    Log.modLog(jsonPath);
                    Log.modLog("Command Count:" + scenario.dataArray.Length.ToString());
                    StreamWriter stream = new StreamWriter(jsonPath);
                    JsonData jsonSum = new JsonData();
                    int index = 0;
                    foreach (ScenarioDataData scenarioDataData in scenario.dataArray)
                    {
                        if (scenarioDataData.COMMANDTYPE == CommandType.Dialogue && scenarioDataData.Text == "")
                        {
                            continue;
                        }
                        JsonData json = new JsonData();
                        json["CommandType"] = scenarioDataData.COMMANDTYPE.ToString();
                        json["Condition"] = scenarioDataData.Condition;
                        json["Id"] = scenarioDataData.Id;
                        json["Text"] = scenarioDataData.Text;
                        json["Value1"] = scenarioDataData.Value1;
                        json["Value2"] = scenarioDataData.Value2;
                        json["Value3"] = scenarioDataData.Value3;
                        json["Value4"] = scenarioDataData.Value4;
                        json["Value5"] = scenarioDataData.Value5;
                        json["Value6"] = scenarioDataData.Value6;
                        json["Value7"] = scenarioDataData.Value7;
                        json["Value8"] = scenarioDataData.Value8;
                        json["Value9"] = scenarioDataData.Value9;
                        json["Value10"] = scenarioDataData.Value10;
                        json["Value11"] = scenarioDataData.Value11;
                        json["Value12"] = scenarioDataData.Value12;
                        json["Value13"] = scenarioDataData.Value13;
                        json["Value14"] = scenarioDataData.Value14;
                        json["Wait"] = scenarioDataData.Wait;

                        jsonSum[index.ToString()] = json;
                        index++;
                    }
                    string s = jsonSum.ToJson();
                    Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
                    s = reg.Replace(s, delegate (Match m) { return ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString(); });
                    stream.Write(s);
                    stream.Close();
                    /*
                    def forjson(load,tar):
	                    f1=open(load,encoding="utf-8")
	                    jsstr=f1.read()
	                    f1.close()
	                    js=json.loads(jsstr)
	                    jsfor=json.dumps(js,indent=4,ensure_ascii=False)
	                    f2=open(tar,"w+",encoding="utf-8")
	                    f2.write(jsfor)
	                    f2.close()
                     格式化json*/
                }
            }
            return true;
        }
        public static void sendMessage(string input)
        {
            Log.modLog("Command:" + input);
            string[] cl = input.Split(new char[] { ' ' });
            switch (cl[0])
            {
                case "hello":
                    Hello();
                    break;
                case "jump":
                    {
                        if (cl.Length != 2)
                        {
                            Log.modLog("Error arg count");
                            break;
                        }
                        int index = int.TryParse(cl[1], out index) ? index : 0;
                        if (!Jump(index))
                        {
                            Log.modLog("Jump Failed");
                        }
                        break;
                    }
                case "changescene":
                    {
                        if (cl.Length != 3)
                        {
                            Log.modLog("Error arg count");
                            break;
                        }
                        if (!GameManager.instance.vnCommands.ContainsKey(cl[1]))
                        {
                            Log.modLog("Don't find the Scenario");
                            break;
                        }
                        if(GameManager.instance.vnCommands[cl[1]].Count <= int.Parse(cl[2]))
                        {
                            Log.modLog("Index is too large");
                            break;
                        }
                        if (!ChangeScene(cl[1], int.Parse(cl[2])))
                        {
                            Log.modLog("ChangeScene Failed");
                        }
                        break;
                    }
                case "voice":
                    {
                        if (cl.Length != 2)
                        {
                            Log.modLog("Error arg count");
                        }
                        if (!Voice(cl[1]))
                        {
                            Log.modLog("Voice Failed");
                        }
                    }
                    break;
                case "sound":
                    {
                        if (cl.Length != 3)
                        {
                            Log.modLog("Error arg count");
                        }
                        if (!Sound(cl[1], cl[2]))
                        {
                            Log.modLog("Sound Failed");
                        }
                    }
                    break;
                case "stop":
                    {
                        if (!Stop())
                        {
                            Log.modLog("Stop Music Failed");
                        }
                    }
                    break;
                case "dump":
                    {
                        if (cl.Length != 2)
                        {
                            Log.modLog("Error arg count");
                        }
                        if (!DumpFile(cl[1]))
                        {
                            Log.modLog("Dump Failed");
                        }
                    }
                    break;
                case "command":
                    {
                        if (cl.Length != 2)
                        {
                            Log.modLog("Error arg count");
                        }
                        if (cl[1] == "true")
                        {
                            isOutCommand = true;
                        }else if (cl[1] == "false")
                        {
                            isOutCommand = false;
                        }
                        else
                        {
                            Log.modLog("Error arg Value, maybe you want to input \"true\" or \"false\"");
                        }
                    }
                    break;
                case "reload":
                    {
                        Reload();
                    }
                    break;
                case "test":
                    {

                    }
                    break;
                default:
                    Log.modLog("Unknow Command");
                    break;
            }
        }
    }
}
